/**
 * @file  diagnostic.c
 * @brief 诊断处理
 * @author liusen
 * @date  2023-6-14
 * @version 0.1
 * @copyright 创为新能源科技股份有限公司
 */

#include "diagnostic.h"
#include "SEGGER_RTT.h"

LIST_HEAD(diagCfgList); //声明初始化诊断链表

static ENU_DETCT_RESULT GetDetcResult(INT16 tCount, UINT16 tPassedLimit, UINT16 tFailedLimit);
static void CalcFaultDetctCounter(INT16 *usCounterPtr, bool bFail);
static bool DiagMessageHandle(STR_DIAG_CFG_NODE *stDiagPtr);

/**
 * @brief 获取诊断结果
 * @param tCount 诊断计数
 * @param tPassedLimit  通过数
 * @param tFailedLimit  失败数
 * @return ENU_DETCT_RESULT 结果
 */
static ENU_DETCT_RESULT GetDetcResult(INT16 tCount, UINT16 tPassedLimit, UINT16 tFailedLimit)
{
    if ((tCount * -1) >= tPassedLimit) // 检测通过
    {
        return DETCT_PASSED;
    }
    else if (tCount == 0) // 未执行过检测
    {
        return DETCT_NOTCHECK;
    }
    else if (tCount >= tFailedLimit) // 检测失败
    {
        return DETCT_FAILED;
    }
    else if (tCount < 0) // 预通过
    {
        return DETCT_PREPASSED;
    }
    else if (tCount > 0)
    {
        return DETCT_PREFAILED; // 预失败
    }

    return DETCT_PASSED;
}

/**
 * @brief 计算失败检测计数
 * @param usCounterPtr 计数指针
 * @param bFail 是否失败 1失败 0未失败
 */
static void CalcFaultDetctCounter(INT16 *usCounterPtr, bool bFail)
{
    if (!bFail) // 通过
    {
        if (*usCounterPtr > 0) // 故障计数处于预失败/失败状态
        {
            *usCounterPtr = -1; // 故障计数反转为-1
        }
        else if (T_DETCT_MIN != *usCounterPtr) // 故障计数不等于该类型的最小值则递减
        {
            (*usCounterPtr)--;
        }
    }
    else // 失败
    {
        if (*usCounterPtr < 0) // 故障计数处于预成功/成功状态
        {
            *usCounterPtr = 1; // 故障计数反转为+1
        }
        else if (T_DETCT_MAX != *usCounterPtr) // 故障计数不等于该类型的最大值则递加
        {
            (*usCounterPtr)++;
        }
    }
}

/**
 * @brief 诊断信息处理
 * @param stDiagPtr 诊断配置节点指针
 * @return bool   1 失败确认 0 无失败确认
 */
static bool DiagMessageHandle(STR_DIAG_CFG_NODE *stDiagPtr)
{
    ENU_DETCT_RESULT eResult = DETCT_NOTCHECK;

    eResult = GetDetcResult(stDiagPtr->sCounter, stDiagPtr->usPassLimit, stDiagPtr->usFailedLimit); //对诊断的结果进行检测 
    
	//DEBUG_LOG_INFO(DEBUG_LEVEL_2, " RESULT IS %d \n",eResult);

	if (DETCT_FAILED == eResult) //检测结果为失败
    {
        stDiagPtr->stDTCStatus.DTCStatusBit.TestFailed = 1; //设置测试失败标志
        if (stDiagPtr->stDTCStatus.DTCStatusBit.ConfirmedDTC == 0) //如果确认失败标志未设置标识的作用是防止多次确认
        {
            stDiagPtr->stDTCStatus.DTCStatusBit.ConfirmedDTC = 1; //设置确认失败标志
            if (stDiagPtr->irfFaultConfirm != NULL) //对检测结果进行失败确认
            {
                stDiagPtr->irfFaultConfirm(true); //确认失败，并允许确认
            }
            return true;
        }
    }
    else if (DETCT_PASSED == eResult) //检测结果为通过
    {
        stDiagPtr->stDTCStatus.DTCStatusBit.TestFailed = 0; // 清除测试失败标志
        if (stDiagPtr->stDTCStatus.DTCStatusBit.ConfirmedDTC == 1 ||
            stDiagPtr->stDTCStatus.DTCStatusBit.testNotCompletedThisOperationCycle == 0)
        {   
            stDiagPtr->stDTCStatus.DTCStatusBit.ConfirmedDTC = 0; // 清理已确认失败标志
            stDiagPtr->stDTCStatus.DTCStatusBit.testNotCompletedThisOperationCycle = 1;
            if (stDiagPtr->irfFaultConfirm != NULL) // 对检测结果进行成功确认
            {
                stDiagPtr->irfFaultConfirm(false); 
            }
            return false;
        }
    }
    return false;
}

/**
 * @brief 增加节点
 * @return int32_t   0 成功 1失败
*/
INT32 DiagAddNode(STR_DIAG_CFG_NODE *diagCfgNodePtr) //增加节点
{
    
    DEBUG_LOG_INFO(DEBUG_LEVEL_2, "---into DiagAddNode---\n");
    
    if(diagCfgNodePtr->usPeriod == 0 || diagCfgNodePtr->usPassLimit == 0 || 
       diagCfgNodePtr->usFailedLimit == 0 || diagCfgNodePtr == NULL)
    {
        return 1;
    }
    list_add_tail(&diagCfgNodePtr->list, &diagCfgList); //尾插
    return 0;
}


/**
 * @brief 诊断主进程，供主动调用，遍历链表节点
 * @attention DIAGNOSIC_PERIOD_MS 需要先定义值
*/
void DiagMainProcess()
{    
    //DEBUG_LOG_INFO(DEBUG_LEVEL_2, "\n---into DiagMainProcess---\n");
    
    static UINT16 usDiagCount = 1; //循环数
    struct list_head *pos;
    STR_DIAG_CFG_NODE *diagPtr;
    list_for_each(pos, &diagCfgList)
    {
        diagPtr = list_entry(pos, STR_DIAG_CFG_NODE, list);
        if (DIAGNOSIC_PERIOD_MS == 0 || diagPtr->usPeriod < DIAGNOSIC_PERIOD_MS)
        {
            return;
        }
        if (usDiagCount % (diagPtr->usPeriod/DIAGNOSIC_PERIOD_MS) == 0)
        {
            CalcFaultDetctCounter(&diagPtr->sCounter, diagPtr->irfDiagFunction());
        }
        DiagMessageHandle(diagPtr);
    }

    if (usDiagCount++ == T_DETCT_MAX)
    {
        usDiagCount = 1;
    }
}

/**
 * @brief 复位 遍历链表，将counter置于0
 * @return int32_t  0成功  1失败
 */
INT32 DiagReset(void)
{
    STR_DIAG_CFG_NODE *diagPtr;
    struct list_head *pos;
    list_for_each(pos, &diagCfgList)
    {
        diagPtr = list_entry(pos, STR_DIAG_CFG_NODE, list);
        diagPtr->sCounter = 0;             
        diagPtr->stDTCStatus.ucDTCStatusByte = 0; 
    }
    return 0;
}

/**
 * @brief 初始化
 * @return int32_t 0成功 1失败
 */
INT32 DiagInit(void)
{
    //TODO 添加到任务中
    return 0;
}